﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;

namespace Summerset.Isbndb.Books
{

    /// <summary>
    /// Represents additional details about a <see cref="BookElement"/>
    /// </summary>
    /// <remarks>
    /// Any of these attributes may not actually have data in the XML node that returns them, 
    /// but they should always exist in the details node.  
    /// To indicate that any of the attributes have an empty string value, we've made all of these
    /// properties nullable, and if an empty string is encountered, a null value will be returned.
    /// </remarks>
    public sealed class BookElementDetail
    {
        #region Constructor + Private Fields

        readonly XmlNode _bookDetailsNode;

        /// <summary>
        /// Initializes a new instance of the <see cref="BookElementDetail"/> class.
        /// </summary>
        /// <param name="BookDetails">The <see cref="XmlNode"/> that contains the book details.</param>        
        public BookElementDetail(XmlNode BookDetails)
        {

            if (!string.Equals(BookDetails.Name, "Details", StringComparison.InvariantCultureIgnoreCase))
                throw new ArgumentException("The provided XmlNode was not valid.  This constructor expects an element named 'Details'");

            _bookDetailsNode = BookDetails;
        }

        #endregion
        #region Properties

        /// <summary>
        /// Gets the date and time of the last change to the book's data.  
        /// This does not indicate the most recent time these fields were checked -- if the server checks
        /// and does not find changes to these details, then the change_time field will not be updated.
        /// </summary>
        /// <remarks>
        /// Retrieve the attribute change_time.
        /// When value is not an empty string, the attribute value will comply with ISO 8601 format, so we can
        /// parse it through the DateTimeOffset.Parse method, without passing any formatting information along with it.
        /// </remarks>
        public DateTimeOffset? DetailsChangeTime
        {
            get
            {

                var attrib = _bookDetailsNode.Attributes["change_time"];

                if (attrib.Value == string.Empty)
                    return null;
                else
                    return DateTimeOffset.Parse(attrib.Value);
            }
        }

        /// <summary>
        /// Gets the date and time of the last prices update for the book. You can use 'prices' results code to retrieve actual price records.
        /// </summary>
        /// <remarks>
        /// Retrieves the attribute price_time.
        /// When value is not an empty string, the attribute value will comply with ISO 8601 format, so we can
        /// parse it through the DateTimeOffset.Parse method, without passing any formatting information along with it.
        /// </remarks>
        public DateTimeOffset? PriceTime
        {
            get
            {

                var attrib = _bookDetailsNode.Attributes["price_time"];

                if (attrib.Value == string.Empty)
                    return null;
                else
                    return DateTimeOffset.Parse(attrib.Value);
            }
        }

        /// <summary>
        /// Free form text describing a particular edition of some text represented by this book.
        /// </summary>
        public string EditionInfo
        {
            get
            {

                var attrib = _bookDetailsNode.Attributes["edition_info"];

                if (attrib.Value == string.Empty)
                    return null;
                else
                    return attrib.Value;
            }
        }        

        /// <summary>
        /// Language code for the book.
        /// </summary>
        public string Language
        {
            get
            {

                var attrib = _bookDetailsNode.Attributes["language"];

                if (attrib.Value == string.Empty)
                    return null;
                else
                    return attrib.Value;
            }
        }        

        /// <summary>
        /// Free form text describing physical characteristics of the book.
        /// </summary>
        public string PhysicalDescription
        {
            get
            {

                var attrib = _bookDetailsNode.Attributes["physical_description_text"];

                if (attrib.Value == string.Empty)
                    return null;
                else
                    return attrib.Value;
            }
        }        

        /// <summary>
        /// Library of Congress Classification number.
        /// </summary>
        public string LCC
        {
            get
            {

                var attrib = _bookDetailsNode.Attributes["lcc_number"];

                if (attrib.Value == string.Empty)
                    return null;
                else
                    return attrib.Value;
            }
        }        

        /// <summary>
        /// Dewey Decimal Classification number for the book as received from libraries.
        /// </summary>
        public string DeweyDecimal
        {
            get
            {

                var attrib = _bookDetailsNode.Attributes["dewey_decimal"];

                if (attrib.Value == string.Empty)
                    return null;
                else
                    return attrib.Value;
            }
        }
        
        /// <summary>
        /// Normalized Dewey Decimal Classification number. Unfortunately, 
        /// in many cases the number as received has inconsistent characters or formatting. 
        /// This attribute represents our best effort at normalizing it.
        /// </summary>
        public string DeweyDecimalNormalized
        {
            get
            {

                var attrib = _bookDetailsNode.Attributes["dewey_decimal_normalized"];

                if (attrib.Value == string.Empty)
                    return null;
                else
                    return attrib.Value;
            }
        }
        
        #endregion
    }
}
